package cn.wolfcode.service.impl;

import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.domain.*;
import cn.wolfcode.mapper.OrderInfoMapper;
import cn.wolfcode.mapper.PayLogMapper;
import cn.wolfcode.mapper.RefundLogMapper;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.IOrderInfoService;
import cn.wolfcode.service.ISeckillProductService;
import cn.wolfcode.util.IdGenerateUtil;
import cn.wolfcode.web.feign.IntegralFeignApi;
import cn.wolfcode.web.feign.PayFeignApi;
import cn.wolfcode.web.msg.SeckillCodeMsg;
import com.alibaba.fastjson.JSON;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * Created by wolfcode-lanxw
 */
@Service
public class OrderInfoSeviceImpl implements IOrderInfoService {
    @Autowired
    private ISeckillProductService seckillProductService;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private PayLogMapper payLogMapper;
    @Autowired
    private RefundLogMapper refundLogMapper;
    @Autowired
    private PayFeignApi payFeignApi;
    @Autowired
    private IntegralFeignApi integralFeignApi;
    @Override
    public OrderInfo findByUserIdAndSeckillId(Long seckillId, String phone) {
        return orderInfoMapper.findByUserIdAndSeckillId(seckillId,phone);
    }

    @Override
    @Transactional
    public String createOrder(SeckillProductVo vo, String phone) {
        //库存的扣减
        int effectCount = seckillProductService.decrStockCount(vo.getId());
        if(effectCount==0){
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }
        //订单创建
        String orderNo = create(vo,phone);
        return orderNo;
    }

    private String create(SeckillProductVo vo, String phone) {
        OrderInfo orderInfo = new OrderInfo();
        //=========================================================
        orderInfo.setIntegral(vo.getIntegral());//商品需要多少积分
        orderInfo.setProductId(vo.getProductId());//关联商品ID
        orderInfo.setProductImg(vo.getProductImg());//商品图片
        orderInfo.setProductName(vo.getProductName());//商品名称
        orderInfo.setProductPrice(vo.getProductPrice());//商品价格
        orderInfo.setSeckillDate(vo.getStartDate());//秒杀日期
        orderInfo.setSeckillPrice(vo.getSeckillPrice());//秒杀价格
        orderInfo.setSeckillTime(vo.getTime());//秒杀场次
        //=========================================================
        orderInfo.setSeckillId(vo.getId());//秒杀ID
        orderInfo.setUserId(Long.parseLong(phone));//用户ID
        orderInfo.setOrderNo(String.valueOf(IdGenerateUtil.get().nextId()));//订单编号
        orderInfo.setCreateDate(new Date());//订单创建时间
        orderInfoMapper.insert(orderInfo);
        return orderInfo.getOrderNo();
    }

    @Override
    public OrderInfo find(String orderNo) {
        String orderKey = SeckillRedisKey.SECKILL_ORDER_HASH.getRealKey("");
        String objStr = (String) redisTemplate.opsForHash().get(orderKey, orderNo);
        return JSON.parseObject(objStr,OrderInfo.class);
    }

    @Override
    @Transactional
    public void cancelPayTimeOutOrder(String orderNo) {
        //1.根据订单编号查询订单状态
        OrderInfo orderInfo = orderInfoMapper.find(orderNo);
        //2.如果是未支付
        if(OrderInfo.STATUS_ARREARAGE.equals(orderInfo.getStatus())){
            //       - 修改订单状态
            int effectCount = orderInfoMapper.updateCancelStatus(orderNo,OrderInfo.STATUS_TIMEOUT);
            if(effectCount==0){
                System.out.println("其他线程已经修改的订单状态");
                return;
            }
            //       - 真实库存回补
            seckillProductService.incrStockCount(orderInfo.getSeckillId());
            //       - 同步预库存
            seckillProductService.syncStockCountToRedis(orderInfo.getSeckillTime(),orderInfo.getSeckillId());
        }
        //3.如果是已支付，不用做任何事情
    }
    @Value("${pay.notifyUrl}")
    private String notifyUrl;
    @Value("${pay.returnUrl}")
    private String returnUrl;
    @Override
    public Result<String> payOnLine(String orderNO) {
        OrderInfo orderInfo = orderInfoMapper.find(orderNO);
        if(OrderInfo.STATUS_ARREARAGE.equals(orderInfo.getStatus())){
            PayVo vo = new PayVo();
            vo.setOutTradeNo(orderInfo.getOrderNo());//订单编号
            vo.setTotalAmount(String.valueOf(orderInfo.getSeckillPrice()));//订单价格
            vo.setSubject(orderInfo.getProductName());//商品名称
            vo.setBody("秒杀订单:"+orderInfo.getProductName());
            vo.setNotifyUrl(notifyUrl);
            vo.setReturnUrl(returnUrl);
            Result<String> result = payFeignApi.pay(vo);
            if(result==null){
                //远程的支付服务无法调用
                return Result.error(SeckillCodeMsg.PAY_SERVER_ERROR);
            }
            return result;
        }else{
            return Result.error(SeckillCodeMsg.ORDER_STATUS_ERROR);
        }
    }

    @Override
    @Transactional
    public void paySuccess(String orderNo) {
       int effectCount =  orderInfoMapper.changePayStatus(orderNo,OrderInfo.STATUS_ACCOUNT_PAID,OrderInfo.PAYTYPE_ONLINE);
       if(effectCount==0){
           //有其他线程已经修改了订单状态,走退款逻辑
       }
    }

    @Override
    public void refundOnline(OrderInfo orderInfo) {
        //远程调用支付的接口
        RefundVo vo = new RefundVo();
        vo.setOutTradeNo(orderInfo.getOrderNo());
        vo.setRefundAmount(String.valueOf(orderInfo.getSeckillPrice()));
        vo.setRefundReason("不想要了");
        Result<Boolean> result = payFeignApi.refund(vo);
        if(result==null || result.hasError()){
            throw new BusinessException(SeckillCodeMsg.PAY_SERVER_ERROR);
        }
        if(!result.getData()){
            throw new BusinessException(SeckillCodeMsg.ALIPAY_ERROR);
        }
        //修改订单的状态
        int effectCount = orderInfoMapper.changeRefundStatus(orderInfo.getOrderNo(), OrderInfo.STATUS_REFUND);
        if(effectCount==0){
            throw new BusinessException(SeckillCodeMsg.ORDER_STATUS_ERROR);
        }
    }

    @Override
    @GlobalTransactional
    public void payByIntegral(String orderNo) {
        OrderInfo orderInfo = orderInfoMapper.find(orderNo);
        if(OrderInfo.STATUS_ARREARAGE.equals(orderInfo.getStatus())){
            //插入流水表
            PayLog log = new PayLog();
            log.setOrderNo(orderNo);
            log.setTotalAmount(orderInfo.getSeckillPrice().longValue());
            log.setPayTime(new Date());
            log.setPayType(OrderInfo.PAYTYPE_INTEGRAL);
            payLogMapper.insert(log);
            //远程调用积分服务积分扣减 TODO
            OperateIntegralVo vo = new OperateIntegralVo();
            vo.setUserId(orderInfo.getUserId());
            vo.setValue(orderInfo.getIntegral());
            Result<Boolean> result = integralFeignApi.pay(vo);
            if(result==null || result.hasError()){
                throw new BusinessException(SeckillCodeMsg.INTEGRAL_SERVER_ERROR);
            }
            if(!result.getData()){
                throw new BusinessException(SeckillCodeMsg.INTEGRAL_NOT_ENOUGH);
            }
            //订单状态的修改
            int effectCount = orderInfoMapper.changePayStatus(orderNo, OrderInfo.STATUS_ACCOUNT_PAID, OrderInfo.PAYTYPE_INTEGRAL);
            if(effectCount==0){
                throw new BusinessException(SeckillCodeMsg.ORDER_STATUS_ERROR);
            }
        }

    }

    @Override
    @Transactional
    public void refundByIntegral(OrderInfo orderInfo) {
        //1.插入流水日志
        RefundLog log = new RefundLog();
        log.setOrderNo(orderInfo.getOrderNo());
        log.setRefundAmount(orderInfo.getIntegral());
        log.setRefundReason("不要了");
        log.setRefundTime(new Date());
        log.setRefundType(OrderInfo.PAYTYPE_INTEGRAL);
        refundLogMapper.insert(log);
        //2.远程调用积分退款
        OperateIntegralVo vo = new OperateIntegralVo();
        vo.setUserId(orderInfo.getUserId());
        vo.setValue(orderInfo.getIntegral());
        Result<Boolean> result = integralFeignApi.refund(vo);
        if(result==null || result.hasError() ){
            throw new BusinessException(SeckillCodeMsg.INTEGRAL_SERVER_ERROR);
        }
        //3.修改状态
        int effectCount = orderInfoMapper.changeRefundStatus(orderInfo.getOrderNo(), OrderInfo.STATUS_REFUND);
        if(effectCount==0){
            throw new BusinessException(SeckillCodeMsg.ORDER_STATUS_ERROR);
        }
    }
}
